﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using AllInOne.Entity;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace AllInOne
{
    

    class BaiduAI
    {
        private static object locker = new object();

        // sdk初始化
        [DllImport("BaiduFaceApi.dll", EntryPoint = "sdk_init", CharSet = CharSet.Ansi
             , CallingConvention = CallingConvention.Cdecl)]
        private static extern int sdk_init(bool id_card);


        // 是否授权
        [DllImport("BaiduFaceApi.dll", EntryPoint = "is_auth", CharSet = CharSet.Ansi
                , CallingConvention = CallingConvention.Cdecl)]
        private static extern bool is_auth();


        // sdk销毁
        [DllImport("BaiduFaceApi.dll", EntryPoint = "sdk_destroy", CharSet = CharSet.Ansi
             , CallingConvention = CallingConvention.Cdecl)]
        private static extern void sdk_destroy();

        //追踪人脸
        [DllImport("BaiduFaceApi.dll", EntryPoint = "track_by_buf", CharSet = CharSet.Ansi
          , CallingConvention = CallingConvention.Cdecl)]
        private static extern IntPtr track_by_buf(byte[] image, int size, int max_track_num);

        //获取人脸属性
        [DllImport("BaiduFaceApi.dll", EntryPoint = "face_attr_by_buf", CharSet = CharSet.Ansi
            , CallingConvention = CallingConvention.Cdecl)]
        private static extern IntPtr face_attr_by_buf(byte[] buf, int size);

        // 人脸1:1比对（传二进制图片buffer）
        [DllImport("BaiduFaceApi.dll", EntryPoint = "match_by_buf", CharSet = CharSet.Ansi
            , CallingConvention = CallingConvention.Cdecl)]
        private static extern IntPtr match_by_buf(byte[] buf1, int size1, byte[] buf2, int size2);


        [DllImport("BaiduFaceApi.dll", EntryPoint = "set_min_face_size", CharSet = CharSet.Ansi
   , CallingConvention = CallingConvention.Cdecl)]
        private static extern void set_min_face_size(int size = 30);

        // 双目RGB和IR静默活体检测（传入二进制图片buffer)
        [DllImport("BaiduFaceApi.dll", EntryPoint = "rgb_ir_liveness_check_by_buf", CharSet = CharSet.Ansi
           , CallingConvention = CallingConvention.Cdecl)]
        private static extern IntPtr rgb_ir_liveness_check_by_buf(byte[] rgb_buf, int rgb_size,
            byte[] ir_buf, int ir_size);


        public static FaceInfo RgbIrLiveness(byte[] rgbBuf,byte[] irBuf) {
            FaceInfo livenessFaceInfo = new FaceInfo();

            try
            {
                IntPtr ptr = rgb_ir_liveness_check_by_buf(rgbBuf, rgbBuf.Length, irBuf, irBuf.Length);
                string buf = Marshal.PtrToStringAnsi(ptr);
                //Console.WriteLine("liveness_check_by_buf res is:" + buf);

                JObject resultJson = (JObject)JsonConvert.DeserializeObject(buf);


                var errno = int.Parse(resultJson["errno"].ToString());
                if (errno > 0)
                {
                    livenessFaceInfo.irScore = 0;
                    livenessFaceInfo.rgbScore = 0;
                    return livenessFaceInfo;
                }
                var scoreJson = (JObject)resultJson["data"];
                float irScore = float.Parse(scoreJson["ir_score"].ToString());
                float rgbScore = float.Parse(scoreJson["rgb_score"].ToString());
                livenessFaceInfo.irScore = irScore;
                livenessFaceInfo.rgbScore = rgbScore;
                return livenessFaceInfo;
            }
            catch (Exception)
            {

                livenessFaceInfo.irScore = 0;
                livenessFaceInfo.rgbScore = 0;
                return livenessFaceInfo;
            }
        }



        public static bool InitSdk(bool idCard)
        {
            try
            {
                int n = sdk_init(idCard);
                if (n != 0)
                {
                    SimpleConsole.WriteInfo("auth result is {0:D}", n);
                }
                set_min_face_size(30);
                return is_auth();
            }
            catch (Exception ex)
            {
                return true;
            }
        }


        public static void DestroySdk()
        {
            sdk_destroy();
        }




        public static FaceInfo TrackFace(byte[] imgBytes)
        {
            lock (locker)
            {
                FaceInfo faceInfo = new FaceInfo();
                int max_track_num = 1; // 设置最多检测人数（多人脸检测），默认为1，最多可设为10
                IntPtr ptr = IntPtr.Zero;
                try
                {
                    ptr = track_by_buf(imgBytes, imgBytes.Length, max_track_num);
                }
                catch (AccessViolationException e)
                {
                    SimpleConsole.WriteError(e.Source + ":" + e.GetType() + ":" + e.Message + ":" + e.StackTrace, new BaiduAI());
                    try
                    {
                        ptr = track_by_buf(imgBytes, imgBytes.Length, max_track_num);
                    }
                    catch (AccessViolationException ex)
                    {
                        SimpleConsole.WriteError(ex.Source + ":" + ex.GetType() + ":" + ex.Message + ":" + ex.StackTrace, new BaiduAI());
                        return null;
                    }
                }
                string buf = Marshal.PtrToStringAnsi(ptr);

                JObject resultJson = null;
                try
                {
                    resultJson = (JObject)JsonConvert.DeserializeObject(buf);
                }
                catch (Exception)
                {

                    try
                    {
                        resultJson = (JObject)JsonConvert.DeserializeObject("{" + buf);
                    }
                    catch (Exception)
                    {
                        return null;
                    }
                }

                var errno = int.Parse(resultJson["errno"].ToString());
                if (errno > 0)
                {
                    return null;
                }

                var faceJson = ((JArray)resultJson["data"]["list"])[0];
                int x = int.Parse(faceJson["center_x"].ToString());
                int y = int.Parse(faceJson["center_y"].ToString());
                int width = int.Parse(faceJson["width"].ToString());
                double roll = double.Parse(((JArray)faceJson["head_pos"])[2].ToString());  //x
                double pitch = double.Parse(((JArray)faceJson["head_pos"])[0].ToString());  //y
                double yaw = double.Parse(((JArray)faceJson["head_pos"])[1].ToString());  //z
                faceInfo.x = x;
                faceInfo.y = y;
                faceInfo.width = width;
                faceInfo.yaw = yaw;
                faceInfo.roll = roll;
                faceInfo.pitch = pitch;
                return faceInfo;
            }
        }


        public static FaceInfo TrackFaceTest(byte[] imgBytes)
        {
            FaceInfo faceInfo = new FaceInfo();
            int max_track_num = 1; // 设置最多检测人数（多人脸检测），默认为1，最多可设为10
            IntPtr ptr = track_by_buf(imgBytes, imgBytes.Length, max_track_num);
            string buf = Marshal.PtrToStringAnsi(ptr);

            JObject resultJson = (JObject)JsonConvert.DeserializeObject(buf);

            var errno = int.Parse(resultJson["errno"].ToString());
            if (errno > 0)
            {
                return null;
            }

            var faceJson = ((JArray)resultJson["data"]["list"])[0];
            int x = int.Parse(faceJson["center_x"].ToString());
            int y = int.Parse(faceJson["center_y"].ToString());
            int width = int.Parse(faceJson["width"].ToString());
            double roll = double.Parse(((JArray)faceJson["head_pos"])[2].ToString());  //x
            double pitch = double.Parse(((JArray)faceJson["head_pos"])[0].ToString());  //y
            double yaw = double.Parse(((JArray)faceJson["head_pos"])[1].ToString());  //z
            faceInfo.x = x;
            faceInfo.y = y;
            faceInfo.width = width;
            faceInfo.yaw = yaw;
            faceInfo.roll = roll;
            faceInfo.pitch = pitch;
            return faceInfo;
        }

        public static FaceInfo GetFaceAttr(byte[] imgBytes)
        {
            lock (locker)
            {
                FaceInfo faceInfo = new FaceInfo();
                IntPtr ptr = face_attr_by_buf(imgBytes, imgBytes.Length);
                string buf = Marshal.PtrToStringAnsi(ptr);

                JObject dataJson = (JObject)JsonConvert.DeserializeObject(buf);

                var errno = int.Parse(dataJson["errno"].ToString());
                if (errno > 0)
                {
                    return null;
                }

                var resultJson = dataJson["data"]["result"];
                int age = (int)double.Parse(resultJson["age"].ToString());
                //float ageConf = float.Parse(resultJson["age_conf"].ToString());

                int gender = int.Parse(resultJson["gender"].ToString());
                float genderConf = float.Parse(resultJson["gender_conf"].ToString());

                int glass = int.Parse(resultJson["glass"].ToString());
                float glassConf = float.Parse(resultJson["glass_conf"].ToString());

                faceInfo.age = age;
                //faceInfo.ageConf = ageConf;
                faceInfo.gender = gender;
                faceInfo.genderConf = genderConf;
                faceInfo.glass = glass;
                faceInfo.glassConf = glassConf;


                return faceInfo;
            }
        }


        public static float CompareFace(byte[] faceBytes1,byte[] faceBytes2)
        {
            lock (locker)
            {
                IntPtr ptr = match_by_buf(faceBytes1, faceBytes1.Length, faceBytes2, faceBytes2.Length);
                string buf = Marshal.PtrToStringAnsi(ptr);

                JObject dataJson = (JObject)JsonConvert.DeserializeObject(buf);

                var errno = int.Parse(dataJson["errno"].ToString());
                if (errno > 0)
                {
                    return 0;
                }

                float score = float.Parse(dataJson["data"]["score"].ToString()) / 100;
                return score;
            }
        }
    }
}
